#include "Person.h"
#include "napi/native_api.h"
#include <cstdlib>
#include <cstring>
#include <string>
#include "simple.h"

static napi_value Add(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);

    return sum;

}

// 用于释放外部数据的回调函数
void finalizeCallback(napi_env env, void *data, void *hint) {
    // 释放外部数据
    free(data);
}

static napi_value NativeCallArkTS(napi_env env, napi_callback_info info)
{    
    size_t argc = 1;
    // 声明参数数组
    napi_value args[1] = {nullptr};

    // 获取传入的参数并依次放入参数数组中
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    // 创建一个int，作为ArkTS的入参
    napi_value argv = nullptr;    
    napi_create_int32(env, 2, &argv );

    // 调用传入的callback，并将其结果返回
    napi_value result = nullptr;
    napi_call_function(env, nullptr, args[0], 1, &argv, &result);
    return result;
}


static napi_value createPerson(napi_env env, napi_callback_info info)
{ 
    size_t argc = 3;
    napi_value args[3] = {nullptr};
    size_t len = 0;
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
    napi_status status = napi_get_value_string_utf8(env, args[0], nullptr, 0, &len);
    if (status != napi_ok) {
        return nullptr;
    }
    char *name = new char[len + 1];
    std::memset(name, 0, len + 1);
    napi_get_value_string_utf8(env, args[0], name, len + 1, &len);
    int32_t age = 0;
    status = napi_get_value_int32(env, args[1], &age);
    if (status != napi_ok) {
        return nullptr;
    }
    double  height = 0.0;
    status = napi_get_value_double(env, args[2], &height);
    if (status != napi_ok) {
        return nullptr;
    }
    Person *person = new Person(name, age, height);
    napi_value result;
    status = napi_create_external(env, person, finalizeCallback, nullptr, &result);
    if (status != napi_ok) {
        return nullptr;
    }
    return result;
}

static napi_value parsePerson(napi_env env, napi_callback_info info)
{ 
    size_t argc = 1;
    napi_value args[1];
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    void* data;
    napi_get_value_external(env, args[0], &data);

    Person* person = static_cast<Person*>(data);
    napi_value result;
    std::string json = "{\"name\":\"" + std::string(person->getName()) + "\",\"age\":" + std::to_string(person->getAge()) + ", \"height\":" + std::to_string(person->getHeight()) + "}";
    napi_status status = napi_create_string_utf8(env, json.c_str(), json.length(), &result);
    if (status != napi_ok) {
        return nullptr;
    }
    return result;
}

static napi_value testGetMessage(napi_env env, napi_callback_info info) {
    const char* message = simpleReturnString();
    napi_value result;
    napi_status status = napi_create_string_utf8(env, message, strlen(message), &result);
    return status == napi_ok ? result : nullptr;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr },
        {"nativeCallArkTS", nullptr, NativeCallArkTS, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"createPerson", nullptr, createPerson, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"parsePerson", nullptr, parsePerson, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"testGetMessage", nullptr, testGetMessage, nullptr, nullptr, nullptr, napi_default, nullptr},
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "learnnapi",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterLearnNAPIModule(void)
{
    napi_module_register(&demoModule);
}
